package com.xxx.server.config.security.component;

import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtTokenUtil {

    //荷载里面准备一个用户名
    private static final String CLAIM_KEY_USERNAME="sub";
    //创建时间
    private static final String CLAIM_KEY_CREATED="created";
    //拿取jwt秘钥，从配置的信息中, @Value 注解方式赋值
    @Value("${jwt.secret}")
    private String secret;
    //失效时间，@Value 注解方式赋值
    @Value("${jwt.expiration}")
    private Long expiration;


    // 1、根据用户信息生成token。 UserDetails是security里面的方法，可以获取用户名
    public String generateToken(UserDetails userDetails){
        //准备荷载
        Map<String, Object> claims = new HashMap<>();
        //设置荷载的名字和创建时间
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }

    //1、2  根据荷载生成JWT token
    private String generateToken(Map<String,Object> claims){
        return Jwts.builder()
                .setClaims(claims)      //设置荷载名
                .setExpiration(generateExpirationDate())        //设置失效时间
                .signWith(SignatureAlgorithm.HS512,secret)      //签名
                .compact();
    }

    //1.3荷载失效时间方法
    private Date generateExpirationDate() {
        //生成的失效时间是当前系统时间加上配置的存活时间
        return new Date(System.currentTimeMillis()+expiration*1000);
    }

    //2、1 从token中获取登陆用户名
    public String getUsernameFromToken(String token){

        String username;
        try{
            Claims claims = getClaimsFromToken(token);  //从token中获取荷载
            username = claims.getSubject(); //  通过getsubject方法获取登录用户名
        } catch (Exception e) {
            username = null;
        }
        return username;
    }
    //2.2 通过解析器，解析token获得荷载
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try{
            claims = Jwts.parser()
                    .setSigningKey(secret)  //设置秘钥
                    .parseClaimsJws(token)  // 解析token
                    .getBody();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return claims;
    }

    //3.1 、判断token 是否有效，荷载中的用户名和UserDetails中的是否一致
    public boolean validateToken(String token,UserDetails userDetails){

        String username = getUsernameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExired(token);
    }

    //3.2 判断token是否过期
    private boolean isTokenExired(String token) {

        Date expireDate = getExpireFromToken(token);//从token中获取失效时间
        return expireDate.before(new Date());//失效时间是不是在当前时间之前
    }

    //3.3 从token中获取失效时间  从荷载中可以直接获取过期时间
    private Date getExpireFromToken(String token) {

        //获取荷载
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    //4.1 判断token是否可用刷新
    public boolean canRefresh(String token){
        return !isTokenExired(token);
    }

    //5.1 refresh刷新token，实质是重新设置荷载生成时间
    public String refresh(String token){
        Claims claims = getClaimsFromToken(token);
        claims.put(CLAIM_KEY_CREATED,new Date());
        return generateToken(claims);
    }


}
